package com.sidom.movieIndexer.matcher;

import java.lang.reflect.Type;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Factory;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Assert;

import com.sidom.movieIndexer.domain.Movie;
import com.sidom.movieIndexer.domain.imdb.ImdbResult;

/**
 * Custom {@link Matcher} that only compares if the {@link ImdbResult}s of a {@link Movie} are the same.
 * @author Siebe
 */
public class ImdbResultMatcher extends TypeSafeMatcher<Movie> {
    /**
     * The expected {@link Movie}
     */
	private final Movie expectedMovie;
	/**
     * The last {@link Movie} that was used for comparison.
     */
	private Movie lastMovie = null;

	/**
	 * Constructor.
	 * @param expectedMovie the expected {@link Movie}.
	 */
    public ImdbResultMatcher(Movie expectedMovie) {
        this.expectedMovie = expectedMovie;
    }

    /**
     * Do a save match.
     * @param movie The {@link Movie} to compare to.
     */
    public boolean matchesSafely(Movie movie) {
    	lastMovie = movie;
    	if(movie==expectedMovie){
			return true;
		}
    	if(movie==null && expectedMovie==null){
			return true;
		}
    	if(movie==null){
			return false;
		}
    	if(expectedMovie==null){
			return false;
		}
    	if(movie.getImdbResult()==null && expectedMovie.getImdbResult()==null){
			return true;
		}
    	if(movie.getImdbResult()==null){
			return false;
		}
    	if(expectedMovie.getImdbResult()==null){
			return false;
		}
    	return EqualsBuilder.reflectionEquals(expectedMovie.getImdbResult(), movie.getImdbResult());
    }
    
    /**
     * The factory.
     * @param <T> Should be a {@link Type}.
     * @param expectedMovie The expected {@link Movie}.
     * @return a {@link Movie} {@link Matcher}.
     */
    @Factory
    public static <T> Matcher<Movie> hasImdbResult(Movie expectedMovie) {
        return new ImdbResultMatcher(expectedMovie);
    }
    
    /**
     * @param description The description if failed.
     */
	@Override
	public void describeTo(Description description) {
		description.appendText("\nExpected imdb result: ");
		description.appendText(expectedMovie.getImdbResult().toString());
		description.appendText("\nbut was imdb result: ");
		description.appendText(lastMovie.getImdbResult().toString());
	}
}
